package ffmpeg

import (
	"context"
	"errors"
	"fmt"
	"golang.org/x/sync/semaphore"
	"log"
	"os/exec"
	"sync"
)

type (
	// CompressVideo 压缩视频
	CompressVideo struct {
		Src  string
		Crf  string
		Args []string
	}
)

// BatchCompressVideo 批量压缩视频
func (f *SFFmpeg) BatchCompressVideo(ctx context.Context, maxWorkers int, videos []CompressVideo) (outFiles []string, err error) {
	if len(videos) == 0 {
		return nil, errors.New(`压缩视频数据为空`)
	}
	var (
		wg      = sync.WaitGroup{}
		sem     = semaphore.NewWeighted(int64(maxWorkers))
		results = make(chan ChanResult, len(videos))
	)
	// 迭代处理
	for _, video := range videos {
		if err = sem.Acquire(ctx, 1); err != nil {
			close(results)
			return nil, err
		}
		wg.Add(1)
		go func(video CompressVideo) {
			defer func() {
				wg.Done()
				sem.Release(1)
			}()
			// 防止CTX失效
			select {
			case <-ctx.Done():
				return
			default:
				var result ChanResult
				result.OutFile, result.Err = f.CompressVideo(video)
				results <- result
			}
		}(video)
	}
	// 等待结束
	wg.Wait()
	close(results)

	// 处理结果集
	return f.processResults(results)
}

// CompressVideo 压缩视频
func (f *SFFmpeg) CompressVideo(compressVideo CompressVideo) (outFile string, err error) {
	defer func() {
		if err != nil {
			log.Printf(`视频压缩失败：%v`, err)
		}
	}()
	// 设置输出文件
	outFile, err = f.outFile(compressVideo.Src, ``, `compress`)
	if err != nil {
		return ``, err
	}
	// 设置命令
	fmt.Println(f.CompressCommandArgs(compressVideo, outFile))
	cmd := exec.Command(f.Driver, f.CompressCommandArgs(compressVideo, outFile)...)
	// 执行命令
	if err = f.executeCommand(cmd); err != nil {
		return "", err
	}
	return outFile, nil
}

// CompressCommandArgs 压缩命令参数
func (f *SFFmpeg) CompressCommandArgs(compressArg CompressVideo, outFile string) []string {
	baseArg := []string{
		`-i`, compressArg.Src,
	}
	if len(compressArg.Args) > 0 {
		baseArg = append(baseArg, compressArg.Args...)
	} else {
		baseArg = append(baseArg, `-vcodec`, `libx264`, `-crf`, compressArg.Crf, `-preset`, `medium`)
	}
	return append(baseArg, outFile)
}
